stm32学习笔记

您所在的位置:网站首页 gpio readoutputdatabit stm32学习笔记

stm32学习笔记

#stm32学习笔记| 来源: 网络整理| 查看: 265

利用STM32固件库学习,记录一些常用的函数:

1、RCC_APB2PeriphClockCmd

用于使能或禁用STM32系列芯片的APB2总线上的外设时钟。该函数定义在STM32固件库中,参数包括要操作的外设的时钟标志和使能或禁用该时钟的命令。

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

其中,RCC_APB2Periph参数是一个32位的值,用于表示要操作的外设时钟,可以使用逻辑或运算符“|”将多个时钟标志组合在一起。

NewState参数是一个枚举类型,用于指示要使能或禁用指定的外设时钟。可选值为:ENABLE和DISABLE。

例1-1:以下代码片段用于使能GPIOA和USART1外设的时钟:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

在操作外设之前,必须先使能其时钟。

2、引脚配置

GPIO_InitTypeDef结构体是STM32固件库中提供给开发者的一个方便、易用的工具,当我们要配置一个GPIO引脚时,需要设置该引脚的多个参数,如引脚方向、输出类型、速度、上拉/下拉模式等,这些参数需要通过寄存器进行设置。而寄存器的操作比较繁琐,容易出错,因此STM32固件库提供了GPIO_InitTypeDef结构体,它封装了对GPIO外设寄存器的访问,使得开发者可以通过设置结构体的成员变量,来快速、简单地配置GPIO引脚的多个参数。

先配置GPIO_InitTypeDef结构体;结构体的定义如下:

typedef struct { uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */ }GPIO_InitTypeDef;

GPIO_Pin表示要配置的GPIO引脚,可以使用逻辑或运算符“|”将多个引脚组合在一起。

GPIO_Mode表示GPIO引脚的工作模式。

输入输出GPIO_Mode_AIN模拟输入GPIO_Mode_Out_OD普通开漏输出GPIO_Mode_IN_FLOATING浮空输入GPIO_Mode_Out_PP普通推挽输出GPIO_Mode_IPU上拉输入GPIO_Mode_AF_OD复用推挽输出GPIO_Mode_IPD下拉输入GPIO_Mode_AF_PP复用开漏输出

GPIO_Speed表示GPIO引脚的速度,可选值为低速(GPIO_Speed_2MHz)、中速(GPIO_Speed_10MHz)或高速(GPIO_Speed_50MHz)。

(STM32 GPIO的8种工作模式及相关配置寄存器_whalefall的博客-CSDN博客)

例2-1:将PA0和PA1两个引脚配置为50MHz的推挽输出,并应用于GPIOA外设。

GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);3、GPIO输出函数GPIO_ResetBits(GPIOA, GPIO_Pin_0); GPIO_SetBits(GPIOA, GPIO_Pin_0); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);

以上代码将GPIOA的PA0引脚输出低/高电平,即将PA0引脚对应的寄存器的输出位设置为0/1。

注意:在操作GPIO引脚之前,必须先配置其为输出模式。否则,GPIO引脚将不能输出电平。

*注意:在很多开发板上,GPIO输出控制LED等外设的亮灭,常常使用了PNP型晶体管或是开漏输出方式。这种方式下,当GPIO引脚输出低电平时,PNP型晶体管或是开漏输出器件会通电,外设(如LED)被点亮,而当GPIO引脚输出高电平时,PNP型晶体管或是开漏输出器件不通电,外设(如LED)被熄灭。

4、GPIO读取函数BitAction GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); BitAction GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

其中,GPIOx是一个指向GPIO外设的指针,可以是GPIOA、GPIOB等GPIO外设的指针。

GPIO_Pin是一个16位的值,用于表示要读取的GPIO引脚编号,可以使用逻辑或运算符“|”将多个引脚组合在一起。

例4-1:以下代码片段用于读取GPIOA的PA5引脚输出状态:

BitAction bitValue = GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5);

例4-2:以下代码片段用于读取GPIOA的PA5引脚输入状态:

BitAction bitValue = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);

注意:GPIO_ReadInputDataBit函数只能读取GPIO引脚的输入状态,不能读取GPIO引脚的输出状态,GPIO_ReadOutputDataBit函数只能读取GPIO引脚的输出状态,不能读取GPIO引脚的输入状态。

注意:读取GPIO引脚的输入状态之前,需要先将对应的引脚配置为输入模式。、

注意:stm32的引脚如果不初始化,默认为浮空输入的形式。

5、配置外部中断EXTI

配置步骤:配置GPIO口->配置AFIO口->配置EXTI->配置NVIC

1)配置GPIO口(同上)

2)配置AFIO:用于将GPIO引脚映射到EXTI线上,从而实现外部中断事件的处理。

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

3)配置EXTI:触发方式与响应方式

EXTI模块的初始化结构体类型GPIO_EXTILineConfig:

typedef struct { uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled. This parameter can be any combination of @ref EXTI_Lines */ EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines. This parameter can be a value of @ref EXTIMode_TypeDef */ EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines. This parameter can be a value of @ref EXTIMode_TypeDef */ FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines. This parameter can be set either to ENABLE or DISABLE */ }EXTI_InitTypeDef;结构体成员EXTI_LineEXTI线号,取值范围为EXTI_Line0到EXTI_Line15。(16-19分别为PVD Output、RTC Alarm、USB、Ethernet Wakeup event)EXTI_ModeEXTI_Mode_Interrupt/EXTI_Mode_EventEXTI_TriggerEXTI_Trigger_Rising/EXTI_Trigger_Falling/EXTI_Trigger_Rising_FallingEXTI_LineCmdENABLE/DISABLEvoid EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); // 初始化EXTI模块

4)配置NVIC:

配置NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器),控制中断优先级和中断处理程序执行。

typedef struct { uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled. This parameter can be a value of @ref IRQn_Type (For the complete STM32 Devices IRQ Channels list, please refer to stm32f10x.h file) */ uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel 配置抢占优先级 specified in NVIC_IRQChannel. This parameter can be a value between 0 and 15 as described in the table @ref NVIC_Priority_Table */ uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified in NVIC_IRQChannel. This parameter can be a value between 0 and 15 as described in the table @ref NVIC_Priority_Table */ FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel will be enabled or disabled. This parameter can be set either to ENABLE or DISABLE */ } NVIC_InitTypeDef;NVIC_IRQChannel成员取值EXTIx_IRQn外部中断线x对应的中断通道号,其中x的取值范围为0~15。UARTx_IRQnUARTx对应的中断通道号,其中x的取值范围为1~8。TIMx_IRQn定时器x对应的中断通道号,其中x的取值范围为1~14。ADCx_IRQnADCx对应的中断通道号,其中x的取值范围为1~3。SPIx_IRQnSPIx对应的中断通道号,其中x的取值范围为1~3。I2Cx_IRQnI2Cx对应的中断通道号,其中x的取值范围为1~3。

NVIC_IRQChannelPreemptionPriority(中断抢占优先级):NVIC_IRQChannelPreemptionPriority成员用于指定中断抢占优先级的值,取值范围为0~15,数值越小表示抢占优先级越高。

NVIC_IRQChannelSubPriority(响应优先级、子优先级):NVIC_IRQChannelSubPriority成员用于指定中断子优先级的值,取值范围为0~15,数值越小表示子优先级越高。

5)编写中断服务程序:

外部中断是通过外部中断线(EXTI)实现的。当外部中断触发时,中断控制器会向CPU发送一个中断请求,CPU会暂停当前的程序执行,转而执行中断服务程序。

在中断服务程序中,需要首先判断触发中断的外部中断线,以确定中断请求的来源。为了实现这一功能,可以使用EXTI_GetITStatus函数来读取相应的中断状态,例如:

if (EXTI_GetITStatus(EXTI_Line0) == SET) { // 处理外部中断事件 // ... // 清除中断标志位 EXTI_ClearITPendingBit(EXTI_Line0); }

其中,EXTI_GetITStatus(EXTI_Line0)函数用于读取外部中断线0的中断状态,如果中断已经触发,则返回SET;否则返回RESET。如果中断已经触发,则执行相应的中断处理程序,并使用EXTI_ClearITPendingBit(EXTI_Line0)函数清除中断标志位,以准备下一次中断。

例5-1:当外部事件发生时,PA0引脚会产生中断请求,从而触发中断服务:

1、配置GPIO引脚:

GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 配置PA0引脚 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 配置为上拉输入模式 GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA

2、配置AFIO模块:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // 将中断事件映射到PA0引脚

3、配置EXTI模块:

EXTI_InitTypeDef EXTI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能AFIO时钟 EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 配置PA0引脚 EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 配置为中断模式 EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 选择上升沿触发中断 EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 使能PA0引脚的中断功能 EXTI_Init(&EXTI_InitStruct); // 初始化EXTI

4、配置NVIC模块:

NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 配置中断线为EXTI0_IRQn NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; // 配置抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; // 配置子优先级 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断线 NVIC_Init(&NVIC_InitStruct); // 初始化NVIC

5、编写中断服务程序:

void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) == SET) // 检测中断请求标志位 { // 执行中断服务程序的操作 // ... EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断请求标志位 } }

注意:最好不要在主程序和中断程序中操作可能产生冲突的硬件,可以优先在中断中操作变量,当中断返回,在对这个变量进行操作。

6、配置定时器中断

配置步骤:配置GPIO口->配置定时器时钟->配置定时器(时钟源->时基单元->输出中断控制)->配置NVIC(使能定时器)->编写中断服务函数->启动定时器

1)配置定时器时钟:RCC_APB1PeriphClockCmd用于控制APB1外设总线上的外设时钟使能和禁止。

函数的原型如下:

void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

2)配置定时器:

2-1)配置定时器时钟源*

a、TIM_InternalClockConfig 输入时钟源来自于内部时钟时钟源

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

TIMx参数指定要配置的定时器,可以是TIM1、TIM2、TIM3等定时器。定时器的时钟源将被设置为内部时钟,即APBx总线时钟。使用内部时钟时,可以通过设置定时器的预分频器和自动重载寄存器来实现不同的定时器周期和频率。

(TIM_InternalClockConfig函数只适用于定时器的基本定时模式,如果需要使用其他定时器模式(例如输入捕获、输出比较等),还需要根据具体的需求进行配置。)

b、TIM_ITRxExternalClockConfig 输入时钟源来自于内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,ITRX是指定计数时钟的输入源。

void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)

TIMx是要配置的定时器,TIM_InputTriggerSource是输入外部时钟的触发源。

c、TIM_TIxExternalClockConfig 输入时钟源来自于外部时钟模式。

void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, uint16_t TIM_ICPolarity, uint16_t ICFilter)

用于配置定时器的输入捕获模式下的输入时钟源。

TIMx是要配置的定时器;

TIM_TIxExternalCLKSource是输入时钟源:TIM_TIxExternalCLK1Source_TI1ED:TI1 的前沿/后沿作为时钟源;TIM_TIxExternalCLK1Source_TI1:TI1 的前沿作为时钟源;TIM_TIxExternalCLK1Source_TI2:TI2 的前沿作为时钟源;

TIM_ICPolarity是输入捕获极性:TIM_ICPolarity_Rising:捕获上升沿;TIM_ICPolarity_Falling:捕获下降沿;TIM_ICPolarity_BothEdge:捕获任意边沿。

ICFilter是输入捕获滤波器的分频系数,取值范围为 0~15,0 表示无滤波器。

e)TIM_ETRClockMode1Config用于配置定时器的外部时钟模式1

f)TIM_ETRClockMode2Config用于配置定时器的外部时钟模式2,外部时钟前提前分频

2-2)配置定时器模式

2-2-1)配置定时器的定时模式(时基单元):TIM_TimeBaseInitTypeDef

typedef struct { uint16_t TIM_Prescaler; // 预分频器值 uint16_t TIM_CounterMode; // 计数模式 uint16_t TIM_Period; // 自动重载值 uint16_t TIM_ClockDivision; // 时钟分割 uint8_t TIM_RepetitionCounter; // 重复计数器值 } TIM_TimeBaseInitTypeDef;结构体成员TIM_Prescaler预分频器值,用于将定时器时钟分频,可取值范围为0~65535。TIM_CounterMode计数模式,TIM_CounterMode_Up(向上计数)、TIM_CounterMode_Down(向下计数)和TIM_CounterMode_CenterAligned1(中心对齐模式1)TIM_Period自动重载值,用于设置定时器的周期,取值范围为0~65535。TIM_ClockDivision时钟分割,用于将定时器时钟进一步分频,可取值范围为TIM_CKD_DIV1(不分割)、TIM_CKD_DIV2和TIM_CKD_DIV4等。TIM_RepetitionCounter高级定时器

2-2-2)输入捕获模式(TIM_ICInitTypeDef)

该模式用于捕获外部信号的上升沿、下降沿或任意边沿,并记录捕获时间。在输入捕获模式下,定时器可以配置为单通道或双通道捕获模式,单通道捕获模式下只捕获一个输入通道的信号,双通道捕获模式下可以同时捕获两个输入通道的信号,并计算它们之间的时间差。该模式可以通过TIM_ICInit函数进行配置。

2-2-3)输出比较模式(TIM_OCInitTypeDef)

该模式用于产生单通道或多通道的 PWM 信号或比较输出信号。在输出比较模式下,定时器可以配置为单通道或多通道输出模式,单通道输出模式下只有一个比较输出通道,多通道输出模式下可以有多个比较输出通道。该模式可以通过TIM_OCInit函数进行配置。

2-2-4)外部时钟模式(TIM_ETRInitTypeDef)

该模式用于将外部信号作为定时器的时钟源,使定时器的计数值随着外部信号的变化而变化。在外部时钟模式下,定时器可以配置为模式 1 或模式 2,模式 1 下外部时钟源可以通过触发输入通道 (TIx) 或外部触发输入 (ETR) 来选择,模式 2 下只能使用 ETR 作为外部时钟源。该模式可以通过TIM_ETRInit函数进行配置。

2-3)配置输出中断控制:

清除定时器中的标志位

void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

调用TIM_ClearFlag函数可以清除定时器中的指定标志位,以准备下一次定时器中断的触发。例如,要清除TIM2定时器的更新中断标志位,可以使用以下代码:

TIM_ClearFlag(TIM2, TIM_FLAG_Update);

使能或禁用定时器的中断:TIM_ITConfig

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);TIMx要操作的定时器TIM_IT中断类型NewStateENABLE、DISABLE

3)配置NVIC(类上EXTI中断)

配置完成后应注意使能定时器。

4)中断服务函数(类上)

用EXTI_GetITStatus(EXTI_Line0) == SET读取状态,并用TIM_ClearITPendingBit(TIM2, TIM_IT_Update);清除中断请求标志位。

例6-1:定时器的周期为1ms,分频系数为7200-1,时钟频率为10kHz。每次定时器中断触发时,计数器值加1,并每1000个定时器周期输出一次计数值。

#include "stm32f10x.h" void TIM2_IRQHandler(void); int main(void) { // 初始化定时器 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1; // 分频系数为7200-1,时钟频率为72MHz/7200=10kHz TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 定时器周期为1ms TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 启用定时器更新中断 TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 启动定时器 TIM_Cmd(TIM2, ENABLE); while (1) { // 在此处添加需要执行的主程序代码 // ... } } void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { static uint32_t count = 0; count++; // 每1000个定时器周期输出一次计数值 if (count == 1000) { count = 0; printf("Timer count: %d\n", count); } // 清除中断标志位 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } }7、其他

stm32f10x_stdperiph_lib_um.chm直接看帮助文档。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3